
NAMESPACE_BEGIN(interp)

    template <class EncodingT>
    Array<EncodingT>::Array()
    {}

    template <class EncodingT>
    Array<EncodingT>::~Array()
    {}

    template <class EncodingT>
    typename EncodingT::string_t Array<EncodingT>::toString() const
    {
        typename EncodingT::string_t str = C("[");
        std::vector< shared_ptr< Base<EncodingT> > >::const_iterator i;
        for (i = m_container.begin(); i != m_container.end(); ++i)
        {
            str += (*i)->toString();
            if (i != m_container.end()-1)
            {
                str += C(";");
            }
        }
        str += C("]");
        return str;
    }

    template <class EncodingT>
    shared_ptr< Base<EncodingT> > Array<EncodingT>::clone() const
    {
        shared_ptr< Array<EncodingT> > obj(new Array<EncodingT>()); 
		
        std::vector< shared_ptr< Base<EncodingT> > >::const_iterator i;
        for (i = m_container.begin(); i != m_container.end(); ++i)
        {
            obj->addValue((*i)->clone());
        }
        return obj;
    }

    template <class EncodingT>
    typename EncodingT::string_t Array<EncodingT>::getClassName() const
    {
        return C("Array");
    }

    template <class EncodingT>
    void Array<EncodingT>::addValue(shared_ptr< Base<EncodingT> > const& val)
    {
        insertValue(size(), val);
    }

    template <class EncodingT>
    void Array<EncodingT>::insertValue(shared_ptr< Base<EncodingT> > const& i, shared_ptr< Base<EncodingT> > const& val)
    {
        double value = 0;     
        if (check_numeric(i, value))
        {
            size_t index = 0;
            if (check_index(value, m_container.size()+1, index))
            {
                m_container.insert(m_container.begin()+index, val);
                String<EncodingT>::setValue(toString());
            }
        }
    }

    template <class EncodingT>
    void Array<EncodingT>::removeValue(shared_ptr< Base<EncodingT> > const& i)
    {
        double value = 0;     
        if (check_numeric(i, value))
        {
            size_t index = 0;
            if (check_index(value, m_container.size(), index))
            {
                m_container.erase(m_container.begin()+index);
                String<EncodingT>::setValue(toString());
            }
        }
    }

    template <class EncodingT>
    shared_ptr< Base<EncodingT> > Array<EncodingT>::getValue(shared_ptr< Base<EncodingT> > const& i) const
    {
        shared_ptr< Base<EncodingT> > res(new Base<EncodingT>);
        double value = 0;     
        if (check_numeric(i, value))
        {
            size_t index = 0;
            if (check_index(value, m_container.size(), index))
            {
                res = m_container[index];
            }
        }
        return res;    
    }

    template <class EncodingT>
    shared_ptr< Base<EncodingT> > Array<EncodingT>::invoke(const typename EncodingT::string_t& method, std::vector< shared_ptr< Base<EncodingT> > >& params)
    {
        shared_ptr< Base<EncodingT> > obj(new Base<EncodingT>());
        
        ParameterArray args, ret;
        if (check_parameters_array(params, args))
        {
            if (tryInvoke(this, C("Array"), method, args, ret) ||
                tryInvoke(this, C("String"), method, args, ret))
            {
                find_parameter(ret, FACTORY_RETURN_PARAMETER, obj);
                for (size_t i = 0; i < params.size(); ++i)
                {
                    find_parameter(ret, i, params[i]);
                }
            }
            else
            {
                Category * logger = &Category::getInstance(LOGNAME);
                logger->errorStream() << "Unexpected call in Array, no method \"" << A(method) << "\" exists.";
            }
        }
        return obj;
    }

    template <class EncodingT>
    shared_ptr< Base<EncodingT> > Array<EncodingT>::size() const
    {
        return shared_ptr< Base<EncodingT> >(new Numeric<EncodingT>(m_container.size()));
    }

    inline bool check_index(double value, size_t size, size_t& index)
    {
        index = (size_t) value;
        bool inside = index < size;
        if (!inside)
        {
            Category * logger = &Category::getInstance(LOGNAME);
            logger->errorStream() << "Index out of range : Index [" << index << "], Max [" << size-1 << "]";
        }
        return inside;
    }
	
    template <class EncodingT, class T>
    shared_ptr< Base<EncodingT> > convert_numeric_array(const bc::vector<T>& value)
	{
		shared_ptr< Array<EncodingT> > arr(new Array<EncodingT>());
		for (size_t i=0; i<value.size(); ++i)
		{
			arr->addValue(shared_ptr< Base<EncodingT> >(new Numeric<EncodingT>(value[i])));
		}
		return arr;
	}

    template <class EncodingT, class T>
    bool check_numeric_array(shared_ptr< Base<EncodingT> > const& val, bc::vector<T>& v)
    {
		double n, numeric;
		shared_ptr< Array<EncodingT> > value  = dynamic_pointer_cast< Array<EncodingT> >(val);
		if (value)
		{
			v.clear();
			if (check_numeric(value->size(), n))
			{
				size_t lg = (size_t)n;
				for (size_t i=0; i<lg; ++i)
				{
					if (check_numeric(
						value->getValue(shared_ptr< Base<EncodingT> >(new Numeric<EncodingT>(i))),
						numeric))
					{
						v.push_back(numeric);
					}
				}
			}
		}
		else
		{
			Category * logger = &Category::getInstance(LOGNAME);
			logger->errorStream() << "Array expected, got " << A(val->getClassName());
		}
		return value;
    }

NAMESPACE_END

